////////////////////////////////////////////////////////////////////////////////////////////////////
/// Copyright (c) 2009 - 2010 RacoonStudios
///
/// Permission is hereby granted, free of charge, to any person obtaining a copy of this
/// software and associated documentation files (the "Software"), to deal in the Software
/// without restriction, including without limitation the rights to use, copy, modify, merge,
/// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
/// to whom the Software is furnished to do so, subject to the following conditions:
///
/// The above copyright notice and this permission notice shall be included in all copies or
/// substantial portions of the Software.
///
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
/// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
/// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
/// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
/// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
/// DEALINGS IN THE SOFTWARE.
////////////////////////////////////////////////////////////////////////////////////////////////////

#pragma once
#ifndef binarywriter_h__
#define binarywriter_h__

#include "iosystem/streamwriter.h"
#include "system/byteorder.h"
#include "math/float2.h"
#include "math/float4.h"
#include "math/point2.h"
#include "math/point4.h"
#include "math/vector2.h"
#include "math/vector3.h"
#include "math/vector4.h"
#include "math/quaternion.h"
#include "math/line2.h"
#include "math/line3.h"
#include "math/rectangle.h"
#include "math/plane.h"
#include "math/sphere.h"

namespace IO
{
	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// \class	BinaryWriter
	///
	/// \brief	This class provides an interface for easily writing binary data to
	///			a stream.
	///
	/// \author	Markus
	/// \date	14.02.2010
	////////////////////////////////////////////////////////////////////////////////////////////////////
	class BinaryWriter : public IO::StreamWriter
	{
		RE_DeclareClass(IO::BinaryWriter);

	public:

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	BinaryWriter()
		///
		/// \brief	Default constructor. 
		///
		/// \author	Markus
		/// \date	14.02.2010
		////////////////////////////////////////////////////////////////////////////////////////////////////
		BinaryWriter();

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	virtual ~BinaryWriter()
		///
		/// \brief	Finaliser. 
		///
		/// \author	Markus
		/// \date	14.02.2010
		////////////////////////////////////////////////////////////////////////////////////////////////////
		virtual ~BinaryWriter();





		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	void SetMemoryMappingEnabled(bool b)
		///
		/// \brief	Sets the possibility of memory mapping for this stream.
		///
		/// \author	Markus
		/// \date	14.02.2010
		///
		/// \param	[in]	b	The memory mapping mode this stream should have. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		void SetMemoryMappingEnabled(bool b);

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	bool IsMempryMappingEnabled() const
		///
		/// \brief	Determines if memory mapping is enabled for this stream.
		///
		/// \author	Markus
		/// \date	14.02.2010
		///
		/// \return	True if memory mapping is enabled for this stream, otherwise false.
		////////////////////////////////////////////////////////////////////////////////////////////////////
		bool IsMemoryMappingEnabled() const;

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	void SetStreamEndianess(System::ByteOrder::Type order)
		///
		/// \brief	Sets the endianess of the stream. 
		///
		/// \author	Markus
		/// \date	14.02.2010
		///
		/// \param	[in]	order	The endianess the strem should have. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		void SetStreamEndianess(System::ByteOrder::Type order);

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	System::ByteOrder::Type GetStreamEndianess() const
		///
		/// \brief	Returns the endianess of the stream.
		///
		/// \author	Markus
		/// \date	14.02.2010
		///
		/// \return	The endianess of the stream.
		////////////////////////////////////////////////////////////////////////////////////////////////////
		System::ByteOrder::Type GetStreamEndianess() const;





		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	virtual bool Open()
		///
		/// \brief	This opens the binary writer.
		///
		/// \author	Markus
		/// \date	14.02.2010
		///
		/// \return	True if the BinaryWriter was successfullly opened, otherwise false.
		////////////////////////////////////////////////////////////////////////////////////////////////////
		virtual bool Open();

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	virtual void Close()
		///
		/// \brief	This cloeses the binary writer again.
		///
		/// \author	Markus
		/// \date	14.02.2010
		////////////////////////////////////////////////////////////////////////////////////////////////////
		virtual void Close();





		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	void WriteChar(char c)
		///
		/// \brief	This writes the specified char onto the stream.
		///
		/// \author	Markus
		/// \date	14.02.2010
		///
		/// \param	[in]	c	The char we want to write to the stream. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		void WriteChar(char c);

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	void WriteUChar(uchar c)
		///
		/// \brief	This writes the specified uchar onto the stream.
		///
		/// \author	Markus
		/// \date	14.02.2010
		///
		/// \param	[in]	c	The uchar we want to write to the stream. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		void WriteUChar(uchar c);

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	void WriteShort(short s)
		///
		/// \brief	This writes the specified short onto the stream.
		///
		/// \author	Markus
		/// \date	14.02.2010
		///
		/// \param	[in]	s	The short we want to write to the stream.
		////////////////////////////////////////////////////////////////////////////////////////////////////
		void WriteShort(short s);

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	void WriteUShort(ushort s)
		///
		/// \brief	This writes the specified ushort onto the stream.
		///
		/// \author	Markus
		/// \date	14.02.2010
		///
		/// \param	[in]	s	The ushort we want to write to the stream. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		void WriteUShort(ushort s);

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	void WriteInt(int i)
		///
		/// \brief	This writes the specified int onto the stream.
		///
		/// \author	Markus
		/// \date	14.02.2010
		///
		/// \param	[in]	i	The int we want to write to the stream. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		void WriteInt(int i);

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	void WriteUInt(uint i)
		///
		/// \brief	This writes the specified uint onto the stream.
		///
		/// \author	Markus
		/// \date	14.02.2010
		///
		/// \param	[in]	i	The uint we want to write to the stream. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		void WriteUInt(uint i);

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	void WriteFloat(float f)
		///
		/// \brief	This writes the specified float onto the stream.
		///
		/// \author	Markus
		/// \date	14.02.2010
		///
		/// \param	[in]	f	The float we want to write to the stream.
		////////////////////////////////////////////////////////////////////////////////////////////////////
		void WriteFloat(float f);

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	void WriteDouble(double d)
		///
		/// \brief	This writes the specified double onto the stream.
		///
		/// \author	Markus
		/// \date	14.02.2010
		///
		/// \param	[in]	d	The double we want to write to the stream.
		////////////////////////////////////////////////////////////////////////////////////////////////////
		void WriteDouble(double d);

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	void WriteBool(bool b)
		///
		/// \brief	This writes the specified bool onto the stream.
		///
		/// \author	Markus
		/// \date	14.02.2010
		///
		/// \param	[in]	b	The bool we want to write to the stream. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		void WriteBool(bool b);

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	void WriteString(const Helper::String & str)
		///
		/// \brief	This writes the specified String onto the stream.
		///
		/// \author	Markus
		/// \date	14.02.2010
		///
		/// \param	[in]	str	The string we want to write to the stream. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		void WriteString(const Helper::String & str);

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	void WriteFloat2(Math::float2 f2)
		///
		/// \brief	This writes the specified float2 onto the stream.
		///
		/// \author	Markus
		/// \date	14.02.2010
		///
		/// \param	[in]	f2	The float2 we want to write to the stream. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		void WriteFloat2(Math::float2 f2);

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	void WriteFloat4(const Math::float4 & f)
		///
		/// \brief	This writes the specified float4 onto the stream.
		///
		/// \author	Markus
		/// \date	14.02.2010
		///
		/// \param	[in]	f	The float4 we want to write to the stream. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		void WriteFloat4(const Math::float4 & f);

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	void WritePoint2(const Math::point2 & p)
		///
		/// \brief	This writes the specified point2 onto the stream.
		///
		/// \author	Markus
		/// \date	14.02.2010
		///
		/// \param	[in]	p	The point2 we want to write to the stream. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		void WritePoint2(const Math::point2 & p);

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	void WritePoint4(const Math::point4 & p)
		///
		/// \brief	This writes the specified point4 onto the stream.
		///
		/// \author	Markus
		/// \date	14.02.2010
		///
		/// \param	[in]	p	The point4 we want to write to the stream. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		void WritePoint4(const Math::point4 & p);

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	void WriteVector2(const Math::vector2 & v)
		///
		/// \brief	This writes the specified vector2 onto the stream.
		///
		/// \author	Markus
		/// \date	14.02.2010
		///
		/// \param	[in]	v	The vector2 we want to write to the stream. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		void WriteVector2(const Math::vector2 & v);

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	void WriteVector3(const Math::vector3 & v)
		///
		/// \brief	This writes the specified vector3 onto the stream.
		///
		/// \author	Markus
		/// \date	14.02.2010
		///
		/// \param	[in]	v	The vector3 we want to write to the stream. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		void WriteVector3(const Math::vector3 & v);

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	void WriteVector4(const Math::vector4 & v)
		///
		/// \brief	This writes the specified vector4 onto the stream.
		///
		/// \author	Markus
		/// \date	14.02.2010
		///
		/// \param	[in]	v	The vector4 we want to write to the stream. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		void WriteVector4(const Math::vector4 & v);

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	void WriteQuaternion(const Math::quaternion & q)
		///
		/// \brief	This writes the specified quaternion onto the stream.
		///
		/// \author	Markus
		/// \date	14.02.2010
		///
		/// \param	[in]	q	The quaternion we want to write to the stream.
		////////////////////////////////////////////////////////////////////////////////////////////////////
		void WriteQuaternion(const Math::quaternion & q);

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	void WritePlane(const Math::plane & p)
		///
		/// \brief	This writes the specified plane onto the stream.
		///
		/// \author	Markus
		/// \date	14.02.2010
		///
		/// \param	[in]	p	The plane we want to write to the stream. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		void WritePlane(const Math::plane & p);

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	void WriteLine2(const Math::line2 & l)
		///
		/// \brief	This writes the specified line2 onto the stream.
		///
		/// \author	Markus
		/// \date	14.02.2010
		///
		/// \param	[in]	l	The line2 we want to write to the stream. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		void WriteLine2(const Math::line2 & l);

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	void WriteLine3(const Math::line3 & l)
		///
		/// \brief	This writes the specified line3 onto the stream.
		///
		/// \author	Markus
		/// \date	14.02.2010
		///
		/// \param	[in]	l	The line3 we want to write to the stream. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		void WriteLine3(const Math::line3 & l);

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	void WriteIntRectangle(const Math::rectangle<int> & r)
		///
		/// \brief	This writes the specified int rectangle onto the stream.
		///
		/// \author	Markus
		/// \date	14.02.2010
		///
		/// \param	[in]	r	The int rectangle we want to write to the stream. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		void WriteIntRectangle(const Math::rectangle<int> & r);

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	void WriteFloatRectangle(const Math::rectangle<float> & r)
		///
		/// \brief	This writes the specified float rectangle onto the stream.
		///
		/// \author	Markus
		/// \date	14.02.2010
		///
		/// \param	[in]	r	The float rectangle we want to write to the stream. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		void WriteFloatRectangle(const Math::rectangle<float> & r);

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	void WriteSphere(const Math::sphere & s)
		///
		/// \brief	This writes the specified sphere onto the stream.
		///
		/// \author	Markus
		/// \date	14.02.2010
		///
		/// \param	[in]	s	The sphere we want to write to the stream. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		void WriteSphere(const Math::sphere & s);

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	void WriteMatrix(const Math::matrix & m)
		///
		/// \brief	This writes the specified matrix onto the stream.
		///
		/// \author	Markus
		/// \date	14.02.2010
		///
		/// \param	[in]	m	The matrix44 we want to write to the stream. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		void WriteMatrix(const Math::matrix & m);

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	void WriteRawData(const void * ptr, tSize bytes)
		///
		/// \brief	This writes the specified raw data block onto the stream.
		///
		/// \author	Markus
		/// \date	14.02.2010
		///
		/// \param	[in]	ptr		The pointer of the data from which we copy. 
		/// \param	[in]	bytes	The amount of bytes we want to write. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		void WriteRawData(const void * ptr, tSize bytes);




		System::ByteOrder m_byteOrder;
		uchar * m_mapCursor;
		uchar * m_mapEnd;

		bool m_enableMapping;
		bool m_isMapped;

	protected:

	private:

	};

}

#endif // binarywriter_h__